package com.yds.developtools.utils.https

import android.util.Log
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import java.io.*
import java.net.HttpURLConnection
import java.net.URL
import java.security.KeyStore
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import java.util.concurrent.*
import javax.net.ssl.*
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlin.reflect.KClass


// 上传/下载进度回调函数类型
typealias ProgressCallback = (progress: Int) -> Unit

/**
 * 轻量级HTTP网络请求工具类，支持GET、POST、PUT、PATCH、DELETE等HTTP方法，
 * 同时提供文件下载、上传和断点续传功能。
 *
 * 使用Kotlin协程实现异步请求，避免阻塞主线程。
 * 提供流式API接口，方便链式调用配置。
 */
class SHttp private constructor() {
    private val executorService: ExecutorService = Executors.newFixedThreadPool(5)  // 处理网络请求的线程池
    private var baseUrl: String = ""  // API基础URL
    private val defaultHeaders: MutableMap<String, String> = mutableMapOf()  // 默认请求头
    private var isLoggingEnabled: Boolean = false  // 是否启用日志输出
    private var trustAllCerts: Boolean = false  // 是否信任所有HTTPS证书（仅用于测试环境）
    private var certificateStream: InputStream? = null  // 自定义HTTPS证书输入流
    private var certificatePassword: String? = null  // 证书密码
    private val activeRequests: ConcurrentHashMap<String, HttpURLConnection> = ConcurrentHashMap()  // 活跃请求集合
    private val activeDownloads: ConcurrentHashMap<String, FileOutputStream> = ConcurrentHashMap()  // 活跃下载集合
    private val gson: Gson = Gson()  // JSON解析库实例

    init {
        defaultHeaders["Accept"] = "application/json"  // 默认接受JSON格式响应
    }

    companion object {
        val instance by lazy { SHttp() }  // 单例实现
    }

    /**
     * 设置API基础URL
     * @param url 基础URL
     * @return 返回当前实例，支持链式调用
     */
    fun setBaseUrl(url: String): SHttp {
        this.baseUrl = url
        return this
    }

    /**
     * 添加默认请求头
     * @param key 请求头键
     * @param value 请求头值
     * @return 返回当前实例，支持链式调用
     */
    fun addHeader(key: String, value: String): SHttp {
        defaultHeaders[key] = value
        return this
    }

    /**
     * 移除默认请求头
     * @param key 请求头键
     * @return 返回当前实例，支持链式调用
     */
    fun removeHeader(key: String): SHttp {
        defaultHeaders.remove(key)
        return this
    }

    /**
     * 启用或禁用日志输出
     * @param enabled 是否启用日志
     * @return 返回当前实例，支持链式调用
     */
    fun enableLogging(enabled: Boolean): SHttp {
        isLoggingEnabled = enabled
        return this
    }

    /**
     * 设置是否信任所有HTTPS证书（不安全，仅用于测试环境）
     * @param trust 是否信任所有证书
     * @return 返回当前实例，支持链式调用
     */
    fun trustAllCertificates(trust: Boolean): SHttp {
        trustAllCerts = trust
        return this
    }

    /**
     * 设置自定义HTTPS证书
     * @param stream 证书输入流
     * @param password 证书密码（可选）
     * @return 返回当前实例，支持链式调用
     */
    fun setCertificate(stream: InputStream, password: String? = null): SHttp {
        certificateStream = stream
        certificatePassword = password
        return this
    }

    /**
     * 发送GET请求
     * @param url 请求URL（相对于baseUrl）
     * @param params 请求参数（可选）
     * @param responseType 响应类型（KClass）
     * @return 返回异步响应结果（HttpResponse）
     */
    suspend fun <T : Any> get(url: String, params: Map<String, String> = emptyMap(), responseType: KClass<T>): HttpResponse<T> {
        return executeRequest("GET", buildUrl(url, params), null, null, responseType)
    }

    /**
     * 发送POST请求（JSON格式）
     * @param url 请求URL（相对于baseUrl）
     * @param body 请求体（JSON字符串，可选）
     * @param bodyType 请求体类型（默认JSON）
     * @param responseType 响应类型（KClass）
     * @return 返回异步响应结果（HttpResponse）
     */
    suspend fun <T : Any> post(url: String, body: String? = null, bodyType: BodyType = BodyType.JSON, responseType: KClass<T>): HttpResponse<T> {
        return executeRequest("POST", baseUrl + url, body, bodyType, responseType)
    }

    /**
     * 发送POST请求（表单格式）
     * @param url 请求URL（相对于baseUrl）
     * @param params 请求参数
     * @param responseType 响应类型（KClass）
     * @return 返回异步响应结果（HttpResponse）
     */
    suspend fun <T : Any> post(url: String, params: Map<String, String>, responseType: KClass<T>): HttpResponse<T> {
        return executeRequest("POST", baseUrl + url, params.toFormUrlEncoded(), BodyType.FORM, responseType)
    }

    /**
     * 发送PUT请求（JSON格式）
     * @param url 请求URL（相对于baseUrl）
     * @param body 请求体（JSON字符串，可选）
     * @param bodyType 请求体类型（默认JSON）
     * @param responseType 响应类型（KClass）
     * @return 返回异步响应结果（HttpResponse）
     */
    suspend fun <T : Any> put(url: String, body: String? = null, bodyType: BodyType = BodyType.JSON, responseType: KClass<T>): HttpResponse<T> {
        return executeRequest("PUT", baseUrl + url, body, bodyType, responseType)
    }

    /**
     * 发送PUT请求（表单格式）
     * @param url 请求URL（相对于baseUrl）
     * @param params 请求参数
     * @param responseType 响应类型（KClass）
     * @return 返回异步响应结果（HttpResponse）
     */
    suspend fun <T : Any> put(url: String, params: Map<String, String>, responseType: KClass<T>): HttpResponse<T> {
        return executeRequest("PUT", baseUrl + url, params.toFormUrlEncoded(), BodyType.FORM, responseType)
    }

    /**
     * 发送PATCH请求（JSON格式）
     * @param url 请求URL（相对于baseUrl）
     * @param body 请求体（JSON字符串，可选）
     * @param bodyType 请求体类型（默认JSON）
     * @param responseType 响应类型（KClass）
     * @return 返回异步响应结果（HttpResponse）
     */
    suspend fun <T : Any> patch(url: String, body: String? = null, bodyType: BodyType = BodyType.JSON, responseType: KClass<T>): HttpResponse<T> {
        return executeRequest("PATCH", baseUrl + url, body, bodyType, responseType)
    }

    /**
     * 发送PATCH请求（表单格式）
     * @param url 请求URL（相对于baseUrl）
     * @param params 请求参数
     * @param responseType 响应类型（KClass）
     * @return 返回异步响应结果（HttpResponse）
     */
    suspend fun <T : Any> patch(url: String, params: Map<String, String>, responseType: KClass<T>): HttpResponse<T> {
        return executeRequest("PATCH", baseUrl + url, params.toFormUrlEncoded(), BodyType.FORM, responseType)
    }

    /**
     * 发送DELETE请求（JSON格式）
     * @param url 请求URL（相对于baseUrl）
     * @param body 请求体（JSON字符串，可选）
     * @param bodyType 请求体类型（默认JSON）
     * @param responseType 响应类型（KClass）
     * @return 返回异步响应结果（HttpResponse）
     */
    suspend fun <T : Any> delete(url: String, body: String? = null, bodyType: BodyType = BodyType.JSON, responseType: KClass<T>): HttpResponse<T> {
        return executeRequest("DELETE", baseUrl + url, body, bodyType, responseType)
    }

    /**
     * 发送DELETE请求（表单格式）
     * @param url 请求URL（相对于baseUrl）
     * @param params 请求参数
     * @param responseType 响应类型（KClass）
     * @return 返回异步响应结果（HttpResponse）
     */
    suspend fun <T : Any> delete(url: String, params: Map<String, String>, responseType: KClass<T>): HttpResponse<T> {
        return executeRequest("DELETE", baseUrl + url, params.toFormUrlEncoded(), BodyType.FORM, responseType)
    }

    /**
     * 下载文件，支持断点续传
     * @param url 文件下载URL
     * @param destinationPath 目标文件路径
     * @param progressCallback 进度回调函数（可选）
     * @param overwrite 是否覆盖已存在的文件（默认true）
     * @return 返回异步响应结果（HttpResponse）
     */
    suspend fun downloadFile(
        url: String,
        destinationPath: String,
        overwrite: Boolean = true,
        progressCallback: ProgressCallback? = null
    ): HttpResponse<File> = suspendCoroutine { continuation ->
        executorService.execute {
            var connection: HttpURLConnection? = null
            var outputStream: FileOutputStream? = null
            var inputStream: InputStream? = null

            try {
                log("Downloading file from: $url to $destinationPath")

                val file = File(destinationPath)
                var downloadedSize: Long = 0

                // 如果文件已存在且需要覆盖，则删除原文件
                if (file.exists() && overwrite) {
                    file.delete()
                    log("Existing file deleted, starting new download")
                }

                connection = openConnection(url).apply {
                    requestMethod = "GET"
                    doInput = true
                    useCaches = false

                    // 设置默认请求头
                    defaultHeaders.forEach { (key, value) ->
                        setRequestProperty(key, value)
                    }

                    // 添加到活跃请求列表
                    activeRequests[url] = this
                }

                val responseCode = connection.responseCode
                if (responseCode !in 200..299) {
                    throw IOException("HTTP error code: $responseCode")
                }

                // 获取文件总大小
                val contentLength = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
                    // API 24+ 直接使用 contentLengthLong
                    connection.contentLengthLong
                } else {
                    // API 18-23 使用 contentLength（可能导致大文件溢出）
                    connection.contentLength.toLong()
                }

                log("File size: $contentLength bytes")

                // 验证文件大小有效性
                if (contentLength <= 0) {
                    throw IOException("Invalid content length received from server")
                }

                // 创建输出流
                outputStream = FileOutputStream(file).also {
                    activeDownloads[url] = it
                }

                inputStream = connection.inputStream
                val buffer = ByteArray(8192)
                var bytesRead: Int
                var totalBytesRead: Long = 0

                while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                    outputStream.write(buffer, 0, bytesRead)
                    totalBytesRead += bytesRead

                    // 计算并回调进度（限制在0-100%）
                    val progress = ((totalBytesRead * 100) / contentLength).toInt().coerceIn(0, 100)
                    progressCallback?.invoke(progress)
                }

                // 从活跃请求列表移除
                activeRequests.remove(url)
                activeDownloads.remove(url)

                log("Download completed: $destinationPath")
                continuation.resume(HttpResponse.Success(responseCode, file))
            } catch (e: Exception) {
                log("Download error: ${e.message}")
                activeRequests.remove(url)
                activeDownloads.remove(url)
                continuation.resume(HttpResponse.Exception(e))
            } finally {
                outputStream?.close()
                inputStream?.close()
                connection?.disconnect()
            }
        }
    }

    /**
     * 上传文件，使用multipart/form-data格式
     * @param url 上传URL
     * @param file 要上传的文件
     * @param fieldName 表单字段名（默认"file"）
     * @param fileName 上传文件名（可选，默认使用原文件名）
     * @param params 额外表单参数（可选）
     * @param progressCallback 进度回调函数（可选）
     * @return 返回异步响应结果（HttpResponse）
     */
    suspend fun uploadFile(
        url: String,
        file: File,
        fieldName: String = "file",
        fileName: String? = null,
        params: Map<String, String> = emptyMap(),
        progressCallback: ProgressCallback? = null
    ): HttpResponse<String> = suspendCoroutine { continuation ->
        executorService.execute {
            var connection: HttpURLConnection? = null
            var outputStream: DataOutputStream? = null
            var inputStream: InputStream? = null

            try {
                log("Uploading file: ${file.path} to $url")

                val boundary = "---------------------------${System.currentTimeMillis()}"  // 分隔符
                val lineFeed = "\r\n"  // 换行符

                connection = openConnection(url).apply {
                    requestMethod = "POST"
                    doInput = true
                    doOutput = true
                    useCaches = false

                    // 设置默认请求头
                    defaultHeaders.forEach { (key, value) ->
                        setRequestProperty(key, value)
                    }

                    // 设置multipart/form-data请求头
                    setRequestProperty("Content-Type", "multipart/form-data; boundary=$boundary")

                    // 添加到活跃请求列表
                    activeRequests[url] = this
                }

                outputStream = DataOutputStream(connection.outputStream)
                val fileSize = file.length()
                var uploadedSize: Long = 0
                var lastReportedProgress = 0  // 记录上次报告的进度

                // 写入表单参数
                params.forEach { (key, value) ->
                    outputStream.writeBytes("--$boundary$lineFeed")
                    outputStream.writeBytes("Content-Disposition: form-data; name=\"$key\"$lineFeed$lineFeed")
                    outputStream.writeBytes("$value$lineFeed")
                }

                // 写入文件
                val finalFileName = fileName ?: file.name
                outputStream.writeBytes("--$boundary$lineFeed")
                outputStream.writeBytes("Content-Disposition: form-data; name=\"$fieldName\"; filename=\"$finalFileName\"$lineFeed")
                outputStream.writeBytes("Content-Type: ${getFileMimeType(file)}$lineFeed")
                outputStream.writeBytes("Content-Transfer-Encoding: binary$lineFeed$lineFeed")

                val fileInputStream = FileInputStream(file)
                val buffer = ByteArray(8192)
                var bytesRead: Int

                while (fileInputStream.read(buffer).also { bytesRead = it } != -1) {
                    outputStream.write(buffer, 0, bytesRead)
                    uploadedSize += bytesRead

                    // 计算进度（限制在0-100%）
                    val currentProgress = ((uploadedSize * 100) / fileSize).toInt().coerceIn(0, 100)

                    // 仅当进度变化超过5%时才回调，避免频繁更新
                    if (currentProgress - lastReportedProgress >= 5 || currentProgress == 100) {
                        progressCallback?.invoke(currentProgress)
                        lastReportedProgress = currentProgress
                    }
                }

                outputStream.writeBytes(lineFeed)
                outputStream.writeBytes("--$boundary--$lineFeed")

                // 发送请求并获取响应
                val responseCode = connection.responseCode
                val responseStream = if (responseCode in 200..299) {
                    connection.inputStream
                } else {
                    connection.errorStream
                }

                val response = BufferedReader(InputStreamReader(responseStream)).use {
                    it.readText()
                }

                // 从活跃请求列表移除
                activeRequests.remove(url)

                log("Upload completed with response code: $responseCode")
                if (responseCode in 200..299) {
                    continuation.resume(HttpResponse.Success(responseCode, response))
                } else {
                    continuation.resume(HttpResponse.Error(responseCode, response))
                }
            } catch (e: Exception) {
                log("Upload error: ${e.message}")
                activeRequests.remove(url)
                continuation.resume(HttpResponse.Exception(e))
            } finally {
                outputStream?.close()
                inputStream?.close()
                connection?.disconnect()
            }
        }
    }

    /**
     * 取消指定URL的请求
     * @param url 请求URL
     */
    fun cancelRequest(url: String) {
        val connection = activeRequests[url]
        connection?.disconnect()
        activeRequests.remove(url)

        // 如果是下载请求，关闭文件输出流
        val outputStream = activeDownloads[url]
        outputStream?.close()
        activeDownloads.remove(url)

        log("Request cancelled: $url")
    }

    /**
     * 取消所有活跃请求
     */
    fun cancelAllRequests() {
        activeRequests.forEach { (url, connection) ->
            connection.disconnect()
            log("Request cancelled: $url")
        }

        activeDownloads.forEach { (_, stream) ->
            stream.close()
        }

        activeRequests.clear()
        activeDownloads.clear()
    }

    /**
     * 执行HTTP请求的核心方法
     * @param method HTTP方法（GET、POST等）
     * @param url 完整请求URL
     * @param body 请求体（可选）
     * @param bodyType 请求体类型（可选）
     * @param responseType 响应类型（KClass）
     * @return 返回异步响应结果（HttpResponse）
     */
    private suspend fun <T : Any> executeRequest(
        method: String,
        url: String,
        body: String?,
        bodyType: BodyType?,
        responseType: KClass<T>
    ): HttpResponse<T> = suspendCoroutine { continuation ->
        executorService.execute {
            var connection: HttpURLConnection? = null
            try {
                log("HTTP $method Request: $url")
                log("Headers: $defaultHeaders")
                if (body != null) {
                    log("Body: $body")
                }

                connection = openConnection(url).apply {
                    requestMethod = method
                    doInput = true
                    useCaches = false

                    // 设置默认请求头
                    defaultHeaders.forEach { (key, value) ->
                        setRequestProperty(key, value)
                    }

                    // 根据请求体类型设置Content-Type
                    if (bodyType != null) {
                        setRequestProperty(
                            "Content-Type", when (bodyType) {
                                BodyType.FORM -> "application/x-www-form-urlencoded"
                                BodyType.JSON -> "application/json"
                            }
                        )
                    }

                    // 添加到活跃请求列表
                    activeRequests[url] = this

                    if (body != null && method != "GET") {
                        doOutput = true
                        DataOutputStream(outputStream).use {
                            it.writeBytes(body)
                            it.flush()
                        }
                    }
                }

                val responseCode = connection.responseCode
                val responseStream = if (responseCode in 200..299) {
                    connection.inputStream
                } else {
                    connection.errorStream
                }

                val response = BufferedReader(InputStreamReader(responseStream)).use {
                    it.readText()
                }

                log("Response Code: $responseCode")
                log("Response: $response")

                // 从活跃请求列表移除
                activeRequests.remove(url)

                // 将JSON响应解析为实体类对象
                val result = parseResponse(response, responseType)

                if (responseCode in 200..299) {
                    continuation.resume(HttpResponse.Success(responseCode, result))
                } else {
                    continuation.resume(HttpResponse.Error(responseCode, response))
                }
            } catch (e: Exception) {
                log("Error: ${e.message}")
                activeRequests.remove(url)
                continuation.resume(HttpResponse.Exception(e))
            } finally {
                connection?.disconnect()
            }
        }
    }

    /**
     * 将JSON响应解析为指定类型的对象
     * @param response JSON响应字符串
     * @param responseType 目标类型的KClass
     * @return 解析后的对象
     */
    private fun <T : Any> parseResponse(response: String, responseType: KClass<T>): T {
        return try {
            // 处理字符串类型，直接返回
            if (responseType == String::class) {
                @Suppress("UNCHECKED_CAST")
                response as T
            }
            // 处理基本数据类型
            else if (responseType == Int::class) {
                @Suppress("UNCHECKED_CAST")
                response.toInt() as T
            } else if (responseType == Boolean::class) {
                @Suppress("UNCHECKED_CAST")
                response.toBoolean() as T
            }
            // 处理集合类型（示例：List<String>）
            else if (responseType.java == List::class.java) {
                @Suppress("UNCHECKED_CAST")
                gson.fromJson<List<Any>>(response, object : TypeToken<List<Any>>() {}.type) as T
            }
            // 处理自定义实体类
            else {
                gson.fromJson(response, responseType.java)
            }
        } catch (e: Exception) {
            log("JSON parsing error: ${e.message}")
            throw e
        }
    }

    /**
     * 打开URL连接，处理HTTPS证书验证
     * @param url 请求URL
     * @return 返回HttpURLConnection对象
     */
    private fun openConnection(url: String): HttpURLConnection {
        val urlObj = URL(url)
        val connection = urlObj.openConnection() as HttpURLConnection

        // 如果是HTTPS连接，处理SSL
        if (connection is HttpsURLConnection) {
            if (trustAllCerts) {
                // 创建信任所有证书的SSL上下文
                val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
                    @Throws(CertificateException::class)
                    override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
                    }

                    @Throws(CertificateException::class)
                    override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
                    }

                    override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
                })

                val sslContext = SSLContext.getInstance("TLS")
                sslContext.init(null, trustAllCerts, SecureRandom())

                connection.sslSocketFactory = sslContext.socketFactory
                connection.hostnameVerifier = HostnameVerifier { _, _ -> true }
            } else if (certificateStream != null) {
                // 使用指定证书
                try {
                    certificateStream?.use { stream ->
                        val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
                        keyStore.load(stream, certificatePassword?.toCharArray())

                        val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
                        tmf.init(keyStore)

                        val sslContext = SSLContext.getInstance("TLS")
                        sslContext.init(null, tmf.trustManagers, SecureRandom())

                        connection.sslSocketFactory = sslContext.socketFactory
                    }
                } catch (e: Exception) {
                    log("Error setting certificate: ${e.message}")
                    throw e
                }
            }
        }

        return connection
    }

    /**
     * 构建完整URL，合并baseUrl和参数
     * @param path 请求路径
     * @param params 请求参数
     * @return 返回完整URL
     */
    private fun buildUrl(path: String, params: Map<String, String>): String {
        val fullUrl = if (path.startsWith("http")) path else baseUrl + path
        if (params.isEmpty()) return fullUrl

        val queryString = params.entries.joinToString("&") { (key, value) ->
            "$key=${value.encodeURLComponent()}"
        }

        return if (fullUrl.contains("?")) {
            "$fullUrl&$queryString"
        } else {
            "$fullUrl?$queryString"
        }
    }

    /**
     * URL编码字符串
     * @return 返回编码后的字符串
     */
    private fun String.encodeURLComponent(): String {
        return java.net.URLEncoder.encode(this, "UTF-8")
    }

    /**
     * 将Map转换为表单编码字符串
     * @return 返回表单编码字符串
     */
    private fun Map<String, String>.toFormUrlEncoded(): String {
        return entries.joinToString("&") { (key, value) ->
            "${key.encodeURLComponent()}=${value.encodeURLComponent()}"
        }
    }


    /**
     * 检查服务器是否支持断点续传
     * @param url 请求URL
     * @return 如果服务器支持断点续传返回true，否则返回false
     */
    fun checkResumeSupport(url: String): Boolean {
        try {
            val connection = openConnection(url).apply {
                requestMethod = "HEAD"
                doInput = true
                useCaches = false

                // 设置默认请求头
                defaultHeaders.forEach { (key, value) ->
                    setRequestProperty(key, value)
                }
            }

            val acceptRanges = connection.getHeaderField("Accept-Ranges")
            val supportsResume = "bytes".equals(acceptRanges, ignoreCase = true)
            connection.disconnect()
            return supportsResume
        } catch (e: Exception) {
            log("Error checking resume support: ${e.message}")
            return false
        }
    }

    /**
     * 获取文件的MIME类型
     * @param file 文件对象
     * @return 返回文件的MIME类型字符串
     */
    fun getFileMimeType(file: File): String {
        // 这里简化处理，实际项目中应该根据文件扩展名或内容检测MIME类型
        val fileName = file.name.lowercase()
        return when {
            fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") -> "image/jpeg"
            fileName.endsWith(".png") -> "image/png"
            fileName.endsWith(".gif") -> "image/gif"
            fileName.endsWith(".pdf") -> "application/pdf"
            fileName.endsWith(".txt") -> "text/plain"
            fileName.endsWith(".json") -> "application/json"
            else -> "application/octet-stream"
        }
    }

    /**
     * 日志输出方法
     * @param message 日志消息
     */
    private fun log(message: String) {
        if (isLoggingEnabled) {
            Log.d("[sHttp_]", message)
        }
    }

}